/**
 * @sw-package inventory
 */
import { mount } from '@vue/test-utils';

const salesChannels = [
    {
        name: 'Storefront',
        id: '7e0e4a256138402c82a20fcbb4fbb858',
    },
    {
        name: 'Headless',
        id: '98432def39fc4624b33213a56b8c944d',
    },
];

const productSortings = [
    {
        key: 'score',
        priority: 10,
        label: 'Top results',
        translated: {
            label: 'Top results',
        },
    },
    {
        key: 'name-asc',
        priority: 2,
        label: 'Name A-Z',
        translated: {
            label: 'Name A-Z',
        },
    },
];

const mockResults = {
    nothing: {
        terms: 'nothing',
        result: {
            elements: [],
        },
    },
    oneResult: {
        terms: 'iron',
        result: {
            elements: [
                {
                    name: 'Durable Iron OpenDoor',
                    extensions: {
                        search: {
                            _score: 28799.999999,
                        },
                    },
                },
            ],
        },
    },
    multipleResults: {
        terms: 'awesome',
        result: {
            elements: [
                {
                    name: 'Awesome Copper Belly-flop Buffet',
                    extensions: {
                        search: {
                            _score: 40320,
                        },
                    },
                },
                {
                    name: 'Awesome Wooden Crystal Qlear',
                    extensions: {
                        search: {
                            _score: 34560,
                        },
                    },
                },
                {
                    name: 'Awesome Silk Ghost Voices',
                    extensions: {
                        search: {
                            _score: 34559.9999,
                        },
                    },
                },
            ],
        },
    },
};

async function createWrapper() {
    return mount(
        await wrapTestComponent('sw-settings-search-live-search', {
            sync: true,
        }),
        {
            global: {
                renderStubDefaultSlot: true,
                stubs: {
                    'sw-container': true,
                    'sw-field-error': true,
                    'sw-simple-search-field': await wrapTestComponent('sw-simple-search-field'),
                    'sw-text-field': await wrapTestComponent('sw-text-field'),
                    'sw-text-field-deprecated': await wrapTestComponent('sw-text-field-deprecated', { sync: true }),
                    'sw-contextual-field': await wrapTestComponent('sw-contextual-field'),
                    'sw-block-field': await wrapTestComponent('sw-block-field'),
                    'sw-base-field': await wrapTestComponent('sw-base-field'),
                    'sw-select-base': await wrapTestComponent('sw-select-base'),
                    'sw-single-select': await wrapTestComponent('sw-single-select'),
                    'sw-highlight-text': await wrapTestComponent('sw-highlight-text'),
                    'sw-select-result': await wrapTestComponent('sw-select-result'),
                    'sw-select-result-list': await wrapTestComponent('sw-select-result-list'),
                    'sw-popover': {
                        props: ['popoverClass'],
                        template: `
                    <div class="sw-popover" :class="popoverClass">
                        <slot></slot>
                    </div>`,
                    },
                    'sw-data-grid': await wrapTestComponent('sw-data-grid'),
                    'sw-product-variant-info': await wrapTestComponent('sw-product-variant-info'),
                    'sw-settings-search-live-search-keyword': await wrapTestComponent(
                        'sw-settings-search-live-search-keyword',
                    ),
                    'sw-settings-search-example-modal': true,
                    'sw-loader': true,
                    'sw-field-copyable': true,
                    'sw-inheritance-switch': true,
                    'sw-ai-copilot-badge': true,
                    'sw-help-text': true,
                    'sw-checkbox-field': true,
                    'sw-context-menu-item': true,
                    'sw-context-button': true,
                    'sw-data-grid-settings': true,
                    'sw-data-grid-column-boolean': true,
                    'sw-data-grid-inline-edit': true,
                    'router-link': true,
                    'sw-data-grid-skeleton': true,
                    'sw-provide': true,
                },

                provide: {
                    repositoryFactory: {
                        create: (entity) => {
                            if (entity === 'product_sorting') {
                                return {
                                    search: () => {
                                        return Promise.resolve(productSortings);
                                    },
                                };
                            }

                            return {
                                search: () => {
                                    return Promise.resolve(salesChannels);
                                },
                            };
                        },
                    },
                    validationService: {},
                    liveSearchService: {
                        search: jest.fn(({ search: terms }) => {
                            if (terms === mockResults.nothing.terms) {
                                return Promise.resolve(mockResults.nothing.result);
                            }

                            if (terms === mockResults.oneResult.terms) {
                                return Promise.resolve(mockResults.oneResult.result);
                            }

                            if (terms === mockResults.multipleResults.terms) {
                                return Promise.resolve(mockResults.multipleResults.result);
                            }

                            return Promise.resolve({});
                        }),
                    },
                },
            },

            props: {
                currentSalesChannelId: null,
                searchTerms: '',
                searchResults: {},
            },
        },
    );
}

describe('src/module/sw-settings-search/component/sw-settings-search-live-search', () => {
    let wrapper;

    beforeEach(async () => {
        wrapper = await createWrapper();
        await flushPromises();
    });

    it('should render the sales channel select', async () => {
        expect(wrapper.find('.sw-settings-search-live-search__sales-channel-select').exists()).toBeTruthy();
    });

    it('should show the search box disabled on no sales channel selected', async () => {
        const searchBox = wrapper.find('.sw-simple-search-field input');
        expect(searchBox.attributes().disabled).toBeDefined();
    });

    it('should enable the search box after set the sales channel id', async () => {
        const searchBox = wrapper.find('.sw-simple-search-field input');
        expect(searchBox.attributes().disabled).toBeDefined();

        const salesChannelSwitch = wrapper.find(
            '.sw-settings-search-live-search__sales-channel-select .sw-select__selection',
        );
        await salesChannelSwitch.trigger('click');
        await flushPromises();
        await wrapper.find('.sw-select-option--0').trigger('click');
        expect(searchBox.attributes().disabled).toBeFalsy();
    });

    it('should show no results message if search keywords is nothing', async () => {
        const salesChannelSwitch = wrapper.find(
            '.sw-settings-search-live-search__sales-channel-select .sw-select__selection',
        );
        await salesChannelSwitch.trigger('click');
        await flushPromises();
        await wrapper.find('.sw-select-option--0').trigger('click');
        await flushPromises();
        const searchBox = wrapper.find('.sw-simple-search-field input');
        await searchBox.setValue(mockResults.nothing.terms);
        await flushPromises();

        await searchBox.trigger('keypress', { key: 'Enter' });
        await flushPromises();

        await wrapper.setData({
            liveSearchResults: mockResults.nothing.result,
        });
        await flushPromises();
        const resultText = wrapper.find('.sw-settings-search-live-search__no-result');
        expect(resultText.text()).toBe('sw-settings-search.liveSearchTab.textNoResult');
        wrapper.vm.liveSearchService.search.mockReset();
    });

    it('should show one result for search', async () => {
        const salesChannelSwitch = wrapper.find(
            '.sw-settings-search-live-search__sales-channel-select .sw-select__selection',
        );
        await salesChannelSwitch.trigger('click');
        await flushPromises();
        await wrapper.find('.sw-select-option--0').trigger('click');
        await flushPromises();
        const searchBox = wrapper.find('.sw-simple-search-field input');
        await searchBox.setValue(mockResults.oneResult.terms);
        await flushPromises();

        await searchBox.trigger('keypress', { key: 'Enter' });
        await flushPromises();

        await wrapper.setData({
            liveSearchResults: mockResults.oneResult.result,
        });
        await flushPromises();

        const firstRow = wrapper.find('.sw-data-grid__row--0');
        expect(firstRow.find('.sw-product-variant-info').exists()).toBeTruthy();

        const scoreCell = firstRow.find('.sw-settings-search-live-search__grid-result__score');
        const scoreOrigin = mockResults.oneResult.result.elements[0].extensions.search._score;
        // The score should be round up
        expect(scoreCell.text()).toBe(Math.round(parseFloat(scoreOrigin)).toString());

        wrapper.vm.liveSearchService.search.mockReset();
    });

    it('should able to click on search glass to search', async () => {
        const salesChannelSwitch = wrapper.find(
            '.sw-settings-search-live-search__sales-channel-select .sw-select__selection',
        );
        await salesChannelSwitch.trigger('click');
        await flushPromises();
        await wrapper.find('.sw-select-option--0').trigger('click');
        await flushPromises();
        const searchBox = wrapper.find('.sw-settings-search-live-search__search_box input');
        await searchBox.setValue(mockResults.oneResult.terms);
        await flushPromises();

        const searchIcon = wrapper.find('.sw-settings-search-live-search__search-icon');
        await searchIcon.trigger('click');
        await flushPromises();

        await wrapper.setData({
            liveSearchResults: mockResults.oneResult.result,
        });
        await flushPromises();

        const firstRow = wrapper.find('.sw-data-grid__row--0');
        expect(firstRow.find('.sw-product-variant-info').exists()).toBeTruthy();
        wrapper.vm.liveSearchService.search.mockReset();
    });

    it('should show multiple results for search', async () => {
        const salesChannelSwitch = wrapper.find(
            '.sw-settings-search-live-search__sales-channel-select .sw-select__selection',
        );
        await salesChannelSwitch.trigger('click');
        await flushPromises();
        await wrapper.find('.sw-select-option--0').trigger('click');
        await flushPromises();
        const searchBox = wrapper.find('.sw-simple-search-field input');
        await searchBox.setValue(mockResults.multipleResults.terms);
        await flushPromises();

        await searchBox.trigger('keypress', { key: 'Enter' });
        await flushPromises();

        await wrapper.setData({
            liveSearchResults: mockResults.multipleResults.result,
        });
        await flushPromises();

        const tableBody = wrapper.find('.sw-data-grid__body');
        const firstRow = wrapper.find('.sw-data-grid__row--0');
        const secondRow = wrapper.find('.sw-data-grid__row--1');
        const thirdRow = wrapper.find('.sw-data-grid__row--2');

        expect(tableBody.findAll('.sw-product-variant-info')).toHaveLength(
            mockResults.multipleResults.result.elements.length,
        );
        expect(firstRow.find('.sw-product-variant-info').exists()).toBeTruthy();
        expect(secondRow.find('.sw-product-variant-info').exists()).toBeTruthy();
        expect(thirdRow.find('.sw-product-variant-info').exists()).toBeTruthy();

        wrapper.vm.liveSearchService.search.mockReset();
    });

    it('should call search service with correct sorting parameter', async () => {
        jest.useFakeTimers();
        wrapper.vm.liveSearchService.search.mockClear();

        const searchSpy = jest.spyOn(wrapper.vm.liveSearchService, 'search');

        // Select sales channel
        const salesChannelSwitch = wrapper.find(
            '.sw-settings-search-live-search__sales-channel-select .sw-select__selection',
        );
        await salesChannelSwitch.trigger('click');
        await flushPromises();

        await wrapper.find('.sw-select-option--0').trigger('click');
        await flushPromises();

        // The component fetches sortings on created, and sets default to 'score'.
        // Let's check if the default is passed first.
        const searchBox = wrapper.find('.sw-simple-search-field input');
        await searchBox.setValue(mockResults.multipleResults.terms);
        await flushPromises();
        jest.runAllTimers();
        await flushPromises();

        expect(searchSpy).toHaveBeenCalledWith(
            expect.objectContaining({
                search: mockResults.multipleResults.terms,
                order: 'score',
            }),
            {},
            {},
            expect.any(Object),
        );

        searchSpy.mockClear();

        const sortingSelect = wrapper.find('.sw-settings-search-live-search__sorting-select');
        await sortingSelect.find('.mt-select__selection').trigger('click');
        await flushPromises();

        // The component sorts by priority, so 'score' (10) is first, 'name-asc' (2) is second.
        await sortingSelect.find('.mt-select-option--1').trigger('click');
        await flushPromises();
        jest.runAllTimers();
        await flushPromises();

        // The search should be triggered on value change of sorting select
        expect(searchSpy).toHaveBeenCalledWith(
            expect.objectContaining({
                order: 'name-asc',
                search: mockResults.multipleResults.terms,
            }),
            {},
            {},
            expect.any(Object),
        );
        jest.useRealTimers();
    });
});
